#include "BilingBlingOut.h"

#define DEFAULT_SPEED 10

BilingBlingOut*BilingBlingOut::create(const char* imgPath, const char* particleFile)
{
	BilingBlingOut* ret = new BilingBlingOut();
	if (ret && ret->init(imgPath, particleFile)) {
		ret->autorelease();
		return ret;
	}
	return NULL;
}

BilingBlingOut::BilingBlingOut():_clipPolygon(NULL), _image(NULL),
	_endCallSender(NULL), _endCallFunc(NULL), _started(false),_method(-1), _p1(0),
	_particleFile(NULL), _speed(DEFAULT_SPEED), _autoRemove(false), _colorSample(true)
{  }

BilingBlingOut::~BilingBlingOut()
{
	CC_SAFE_DELETE(_image);
}

bool BilingBlingOut::init(const char* imgPath, const char* particleFile, bool colorSample)
{
	if (!imgPath || !particleFile)
		return false;
	if (!CCNode::init())
		return false;
	_particleFile = particleFile;
	_colorSample = colorSample;

	_clipPolygon = CCDrawNode::create();
	CCClippingNode* clipN = CCClippingNode::create(_clipPolygon);
	this->addChild(clipN, 1);

	CCSprite* sp = CCSprite::create(imgPath);
	sp->setAnchorPoint(CCPointZero);
	clipN->addChild(sp);
	this->setContentSize(sp->getContentSize());

	CCTexture2DPixelFormat s = CCTextureCache::sharedTextureCache()->textureForKey(imgPath)->getPixelFormat();
	if (s != kCCTexture2DPixelFormat_RGBA8888 && s != kCCTexture2DPixelFormat_RGB888) {
		CCLog("只支持RGBA8888和RGB888的图片格式");
		return false;
	}
	_image = new CCImage();
	if (!_image->initWithImageFile(CCFileUtils::sharedFileUtils()->fullPathForFilename(imgPath).c_str())) {
		return false;
	}
	_imgH = _image->getHeight();
	_imgW = _image->getWidth();
	_imgWH = _imgW + _imgH;
	_method = TR2LB;
	reset();
	return true;
}

void BilingBlingOut::update(float delta)
{
	if (!_started) return;
	if (toEnd()) {
		if ((this->getChildrenCount() < 2)) {
			this->unscheduleUpdate();
			if (_endCallSender && _endCallFunc) {
				(_endCallSender->*_endCallFunc)();
			}
			if (_autoRemove)
				this->removeFromParent();
		}
	} else {
		_clipPolygon->clear();
		int pn = 3;
		CCPoint points[5];
		// 点按照逆时针方向排列，让动态点落在0和pn-1上
		CCPoint offset(0, 0);
		CCPoint GPos;
		switch (_method) {
		case T2B:
			pn = 4;
			points[0].x = points[1].x = 0;
			points[0].y = points[3].y = _imgH - _p1;
			points[1].y = points[2].y = 0;
			points[2].x = points[3].x = _imgW;
			offset.x = 10;
			offset.y = -10;
			GPos.setPoint(0, _imgH);
			break;
		case B2T:
			pn = 4;
			points[0].x = points[1].x = _imgW;
			points[0].y = points[3].y = _p1;
			points[1].y = points[2].y = _imgH;
			points[2].x = points[3].x = 0;
			offset.x = 10;
			offset.y = 20;
			GPos.setPoint(0, 0);
			break;
		case L2R:
			pn = 4;
			points[0].x = points[3].x = _p1;
			points[0].y = points[1].y = 0;
			points[1].x = points[2].x = _imgW;
			points[2].y = points[3].y = _imgH;
			offset.x = 10;
			offset.y = 0;
			GPos.setPoint(0, 0);
			break;
		case R2L:
			pn = 4;
			points[0].x = points[3].x = _imgW - _p1;
			points[0].y = points[1].y = _imgH;
			points[1].x = points[2].x = 0;
			points[2].y = points[3].y = 0;
			offset.x = -10;
			offset.y = 0;
			GPos.setPoint(_imgW, 0);
			break;
		case TL2BR:
			if (_p1 <= _imgH) {
				++pn;
				points[0].x = 0;
				points[0].y = _imgH - _p1;
				points[1].x = points[1].y = points[2].y = 0;
				points[2].x = _imgW;
			} else {
				points[0].x = _p1 - _imgH;
				points[0].y = points[1].y = 0;
				points[1].x = _imgW;
			}
			points[pn - 1].x = _imgW;
			if (_p1 < _imgW) {
				points[pn - 1].y = points[pn].y  = _imgH;
				points[pn].x = _p1;
				++pn;
			} else {
				points[pn - 1].y = _imgWH - _p1;
			}
			offset.x = 10;
			offset.y = -10;
			GPos.setPoint(0, _imgH);
			break;
		case BR2TL:
			if (_p1 <= _imgH) {
				++pn;
				points[0].x = points[1].x = _imgW;
				points[0].y = _p1;
				points[1].y = points[2].y = _imgH;
				points[2].x = 0;
			} else {
				points[0].x = _imgWH - _p1;
				points[0].y = points[1].y = _imgH;
				points[1].x = 0;
			}
			points[pn - 1].x = 0;
			if (_p1 < _imgW) {
				points[pn - 1].y = points[pn].y  = 0;
				points[pn].x = _imgW - _p1;
				++pn;
			} else {
				points[pn - 1].y = _p1 - _imgW;
			}
			offset.x = -10;
			offset.y = -10;
			GPos.setPoint(_imgW, 0);
			break;
		case TR2LB:
			if (_p1 <= _imgW) {
				++pn;
				points[0].x = _imgW - _p1;
				points[0].y = points[1].y = _imgH;
				points[1].x = points[2].x = 0;
				points[2].y = 0;
			} else {
				points[0].x = points[1].x = 0;
				points[0].y = _imgWH - _p1;
				points[1].y = 0;
			}
			points[pn - 1].y =  0;
			if (_p1 < _imgH) {
				points[pn - 1].x = points[pn].x = _imgW;
				points[pn].y  = _imgH - _p1;
				++pn;
			} else {
				points[pn - 1].x = _imgWH - _p1;
			}
			offset.x = -10;
//			offset.y = -10;
			GPos.setPoint(_imgW, _imgH);
			break;
		case LB2TR:
			if (_p1 <= _imgW) {
				++pn;
				points[0].x = _p1;
				points[0].y = points[1].y = 0;
				points[1].x = points[2].x = _imgW;
				points[2].y = _imgH;
			} else {
				points[0].x = points[1].x = _imgW;
				points[0].y = _p1 - _imgW;
				points[1].y = _imgH;
			}
			points[pn - 1].y =  _imgH;
			if (_p1 < _imgH) {
				points[pn - 1].x = points[pn].x = 0;
				points[pn].y  = _p1;
				++pn;
			} else {
				points[pn - 1].x = _p1 - _imgH;
			}
			offset.x = 10;
//			offset.y = 10;
			GPos.setPoint(0, 0);
			break;
		}

		// 重新绘制多边形
		_clipPolygon->drawPolygon(points, pn, ccc4f(1,1, 1,1), 0.0f, ccc4f(1,1,1,1));

		// 计算发射的方向
		int linen = (int)(ccpDistance(points[0], points[pn - 1]) / 20);
		float stepX = (points[pn-1].x - points[0].x) / linen;
		float stepY = (points[pn-1].y - points[0].y) / linen;
		for (int i = 0; i < linen; ++i) {
			if (points[0].x < 0 || points[0].y < 0)
				return;
			// 获取像素点颜色
			CCParticleSystemQuad* pp = NULL;
			if (_colorSample) {
				unsigned char* pixColor = NULL;
				float alpha = 255.0f;
				if (_image->hasAlpha()) {
					pixColor = _image->getData() +  4  * ((int)points[0].x + _imgW * (_imgH - (int)points[0].y));
					if (0 == *(pixColor + 3)) {
						points[0].x += stepX;
						points[0].y += stepY;
						continue;
					}
					alpha = (float)(*(pixColor + 3));
				} else {
					pixColor = _image->getData() + 3  * ((int)points[0].x + _imgW * (_imgH - (int)points[0].y));
				}
				pp = CCParticleSystemQuad::create(_particleFile);
				ccColor4F emitColor = {(float)(*pixColor/255.0f), (float)(*(pixColor+1)/255.0f), (float)(*(pixColor + 2)/255.0f), alpha/255.0f};
				pp->setStartColor(emitColor);
				pp->setEndColor(emitColor);
			} else {
				pp = CCParticleSystemQuad::create(_particleFile);
			}

			pp->setPosition(ccpAdd(points[0], offset));
			pp->setGravity(GPos);
			pp->setAutoRemoveOnFinish(true);
			points[0].x += stepX;
			points[0].y += stepY;
			this->addChild(pp, 2);
		}
	}
}

void BilingBlingOut::setSpeed(const long sp)
{
	if (sp < 1) {
		_speed = DEFAULT_SPEED;
	} else {
		_speed = sp;
	}
}

void BilingBlingOut::reset()
{
	if (_started) {
		_started = false;
		this->unscheduleUpdate();
	}
	_p1 = 0;
	_clipPolygon->clear();
	CCPoint points[4];
	points[0].x = points[3].x = 0;
	points[0].y = points[1].y = 0;
	points[1].x = points[2].x = _imgW;
	points[2].y = points[3].y = _imgH;
	_clipPolygon->drawPolygon(points, 4, ccc4f(1,1, 1,1), 0.0f, ccc4f(1,1,1,1));
}

bool BilingBlingOut::toEnd()
{
	if (!_started)
		return false;
	bool r;
	switch (_method) {
	case T2B:
	case B2T:
		r = (_p1 >= _imgH);
		break;
	case L2R:
	case R2L:
		r = (_p1 >= _imgW);
		break;
	case TL2BR:
	case BR2TL:
	case TR2LB:
	case LB2TR:
		r = (_p1 >= _imgWH);
		break;
	}
	_p1 += _speed;
	return r;
}
